package com.shelpe.services.sustainer.development;

import java.util.Calendar;
import java.util.Date;
import java.util.List;

import org.apache.commons.lang3.time.DateUtils;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.JobParametersInvalidException;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.job.builder.SimpleJobBuilder;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException;
import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException;
import org.springframework.batch.core.repository.JobRestartException;
import org.springframework.batch.core.step.builder.SimpleStepBuilder;
import org.springframework.batch.item.support.ListItemReader;
import org.springframework.batch.item.support.ListItemWriter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import org.springframework.scheduling.annotation.Scheduled;

import com.shelpe.services.sustainer.client.RankingClient;
import com.shelpe.services.sustainer.entity.jpa.DevelopmentPlan;
import com.shelpe.services.sustainer.repository.jpa.DevelopmentPlanRepository;
import com.shelpe.services.sustainer.step.BlankEnderStep;
import com.shelpe.services.sustainer.step.BlankStarterStep;
import com.shelpe.services.sustainer.step.InprogressCleanerStep;
import com.shelpe.services.sustainer.step.InprogressRecordStep;

import lombok.extern.slf4j.Slf4j;

@Configuration
@Slf4j
public class DevelopmentPlanConfiguration {

	@Autowired
	private StepBuilderFactory steps;
	@Autowired
	private JobBuilderFactory jobs;
	
	@Autowired
	private JobLauncher jobLauncher;
	@Autowired
	private BlankStarterStep starter;
	@Autowired
	private BlankEnderStep ender;
	@Autowired
	private InprogressRecordStep inprogressRecorder;
	@Autowired
	private InprogressCleanerStep inprogressCleaner;
	@Autowired
	private DevelopmentPlanRepository developmentPlanRepository;
	@Autowired
	private RankingClient rankingClient;
	
	@Scheduled(cron = "0 */5 * * * ?")
	public void developmentExecute() {
		try {
			JobParameters jobParams = new JobParametersBuilder().addLong("version", (new Date()).getTime()).toJobParameters();
			jobLauncher.run(this.developmentExecuteJob(), jobParams);
		} catch (JobExecutionAlreadyRunningException | JobRestartException | JobInstanceAlreadyCompleteException
				| JobParametersInvalidException e) {
			e.printStackTrace();
		}
	}

	@Bean(name="developmentExecuteJob")
	@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
	public Job developmentExecuteJob() {
		SimpleJobBuilder builder = this.jobs.get("developmentExecuteJob").start(starter);
		builder.next(inprogressRecorder).next(this.developmentExecuteStep()).next(inprogressCleaner).next(ender);
		return builder.build();
	}
	@Bean(name = "developmentExecuteStep")
	@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
	public Step developmentExecuteStep() {
		SimpleStepBuilder<DevelopmentPlan, DevelopmentPlanResult> builder = this.steps.get("developmentExecuteStep").chunk(5);
		builder.reader(developmentExecuteItemReader()).processor(this.executeDevelopmentProcessor()).writer(this.developmentExecuteItemWriter());
		builder.faultTolerant().retry(Exception.class).retryLimit(10);
		return builder.build();
	}
	@Bean
	public ExecuteDevelopmentProcessor executeDevelopmentProcessor(){
		ExecuteDevelopmentProcessor processor = new ExecuteDevelopmentProcessor();
		processor.setRankingClient(rankingClient);
		return processor;
	}
	public ListItemWriter<DevelopmentPlanResult> developmentExecuteItemWriter(){
		return new ListItemWriter<DevelopmentPlanResult>();
	}
	public ListItemReader<DevelopmentPlan> developmentExecuteItemReader(){
		Date now = DateUtils.truncate(new Date(), Calendar.SECOND);
		List<DevelopmentPlan> plans = this.developmentPlanRepository.findByStatusAndNextTimeBefore(1, now);
		if(log.isDebugEnabled()){
			log.debug("will execute {} rankings", plans.size());
		}
		return new ListItemReader<DevelopmentPlan>(plans);
	}
	
}
